/***********************************************************************************************************************
 * ############################################# Application AdewebLite #############################################
 * AdewebLite Android est une application permettant de consulter des emplois du temps fournis par l'université UHP
 * avec ou sans connexion internet (informations gardées en mémoire à chaque synchronisation). Et utilisant la web
 * API ADE pour collecter les données.
 * @author Andrianjafintrimo Victor, Zanette Sébastien
 * 
 * Basée sur l'application du même nom, utilisant le flux RSS (données à traiter), de :
 * @author Schnell Michaël, Zanette Sébastien
 * **********************************************************************************************************************
 */

package ade.screen;

import ade.database.Database;
import ade.exception.AAAException;
import ade.main.R;
import ade.schedule.Schedule;
import ade.schedule.ScheduleListAdapter;
import ade.schedule.UpdateListener;
import ade.schedule.UpdateManager;
import greendroid.app.GDActivity;
import greendroid.graphics.drawable.ActionBarDrawable;
import greendroid.widget.ActionBarItem;
import greendroid.widget.ActionBarItem.Type;
import greendroid.widget.LoaderActionBarItem;
import greendroid.widget.NormalActionBarItem;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

/**
 * Vue d'accueil affichant la liste des emplois du temps de l'application. Permet d'ajouter un emploi du temps.
 * Liste des emplois du temps avec leur niveau de synchronisation associé.
 * Ajout d'un emploi du temps.
 * Synchronisation des emplois du temps.
 * @author Seb
 */
public class WelcomeScreen extends GDActivity implements UpdateListener{

	// Nombre d'instance courante
	private static int n = 0;
	// Nombre d'instance (0 = 1ere instance crée, 1 = deuxieme ...)
	private int thisN;
	private ListView liste;
	private ScheduleListAdapter adapter;
	private String nameCurrentSchedule;
	//GDActionBar
	private final int REFRESH = 0;
	protected Database db;

	/**
	 * Applé lorsque la vue est crée la 1er fois.
	 * @param savedInstanceState 
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		if (!Database.isBuilt()) {
			Database.createInstance(this) ;
		}// if
		super.onCreate(savedInstanceState);

		//on attache le listener servant à synchroniser les emplois du temps
		if (UpdateManager.getInstance() == null) {
			UpdateManager.resume() ;
		}// if
		UpdateManager.getInstance().addListener(this) ;

		this.thisN = WelcomeScreen.n++;
		this.setTitle("Emploi du temps");
		this.setActionBarContentView(R.layout.welcome_screen);
		this.initActionBar();
		this.createScheduleList();
		this.initializeAddSchedule();
	}// onCreate(Bundle)

	/**
	 * Initialise la barre d'action de la vue.
	 */
	public void initActionBar() {
		this.addActionBarItem(Type.Refresh, REFRESH);
		this.addActionBarItem(getActionBar().newActionBarItem(NormalActionBarItem.class).setDrawable(new ActionBarDrawable(this, R.drawable.ic_action_bar_info)), R.id.action_bar_view_info);
	}

	/**
	 * Vérifie si l'appareil est connecté à Internet
	 * @return vrai si l'appareil est connecté à Internet, faux sinon
	 */
	public boolean isNetworkAvailable() {
		ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
		return activeNetworkInfo != null;
	}

	/**
	 * Définition des actions des éléments de la barre d'action.
	 */
	@Override
	public boolean onHandleActionBarItemClick(ActionBarItem item, int position) {
		switch (item.getItemId()) {
		case REFRESH:
			if (this.adapter.getCount() == 0) {
				LoaderActionBarItem refreshItem = (LoaderActionBarItem) item;
				refreshItem.setLoading(false);
			} else {
				//Lancer la Synchronisation
				if(this.isNetworkAvailable()){
					this.updateAllSchedules() ;
				}else{
					Toast.makeText(this,"Synchronisation impossible", Toast.LENGTH_LONG).show() ;
					LoaderActionBarItem refreshItem = (LoaderActionBarItem) item;
					refreshItem.setLoading(false);
				}
			}
			break;

		case R.id.action_bar_view_info:
			startActivity(new Intent(this, InfoTabActivity.class));
			return true;

		default:
			return super.onHandleActionBarItemClick(item, position);
		}
		return true;
	}

	/**
	 * Retroure et affiche les noms des emplois du temps stockés par ordre alphabétique.
	 */
	protected void createScheduleList() {
		if (this.liste == null) {
			this.liste = (ListView) this.findViewById(R.id.listSchedule) ; 
			liste.setEmptyView(findViewById(R.id.empty));                              
		}// if

		this.db = new Database() ;
		this.adapter = new ScheduleListAdapter(this, db.getSchedulesName()) ;
		liste.setAdapter(this.adapter) ;
		registerForContextMenu(liste);

		liste.setOnItemClickListener(new AdapterView.OnItemClickListener() {
			public void onItemClick(AdapterView<?> a, View v, int position, long id) {
				Intent intent = new Intent(WelcomeScreen.this, ScheduleScreen.class) ;
				nameCurrentSchedule = adapter.getItem(position);
				intent.putExtra("ade.screen.nameCurrentSchedule", nameCurrentSchedule);
				WelcomeScreen.this.startActivity(intent) ;
			}
		});
	}// createScheduleList()

	/**
	 * Appelé à la recréation de la vue, met à jour la liste d'emplois du temps.
	 */
	@Override
	protected void onRestart() {
		super.onRestart();
		this.createScheduleList();
	}// onRestart()

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {            
		this.getMenuInflater().inflate(R.layout.welcome_screen_menu, menu);
		return super.onCreateOptionsMenu(menu);
	}// onCreateOptionsMenu(Menu)

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.itemOptions :
			this.editOptions() ;
			break ;
		}
		return false ;
	}// onOptionsItemSelected(MenuItem

	/**
	 * Affiche un menu contextuel aprés unclique long sur un élément de la liste.
	 * @param	menu  
	 * 			the context menu that is being built 
	 * @param	v
	 * 			the view for which the context menu is being built 
	 * @param	menuInfo
	 * 			extra information about the item for which the context menu should
	 * 			be shown
	 */
	@Override
	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
		AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
		nameCurrentSchedule = adapter.getItem(info.position);
		super.onCreateContextMenu(menu, v, menuInfo);
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.layout.context_menu_schedule, menu);
		menu.setHeaderTitle(nameCurrentSchedule);
	}
	/**
	 * Définition des actions lors de l'appui sur une des différentes options du menu contextuel.
	 * @param	item
	 * 			the context menu item that was selected
	 * @return  
	 */
	@Override
	public boolean onContextItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.modify:
			Intent intent = new Intent(WelcomeScreen.this,
					EditScheduleScreen.class) ; //Permet de passer le nom de l'emploi du temps à l'activité EditScheduleScreen
			intent.putExtra("ade.screen.nameCurrentSchedule", nameCurrentSchedule); 
			this.startActivity(intent) ;
			return true;
		case R.id.delete:
			this.deleteSchedule();
			return true;
		case R.id.info:
			this.detailsDisplay();
			return true;

		default:
			return super.onContextItemSelected(item);
		}
	}

	/**
	 * Initialise la fonctionnalité "ajout d'un emploi du temps".
	 * <p>Add a listener to the "add" button.
	 */
	private void initializeAddSchedule() {
		final Button button = (Button) findViewById(R.id.add);
		button.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				WelcomeScreen.this.addSchedule();
			}// onClick(View)
		});
	}// initializeAddSchedule()

	/**
	 * Supression d'un emploi du temps.
	 */
	private void deleteSchedule() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setMessage("Confirmation de suppression.").setTitle(nameCurrentSchedule);
		builder.setIcon(RESULT_OK);
		//Valider la suppression
		builder.setPositiveButton("OUI", new DialogInterface.OnClickListener() {
			//@Override

			//Supression de l'edt
			public void onClick(DialogInterface dialog, int which) {
				Database db = new Database() ;
				db.removeScheduleWithName(nameCurrentSchedule);
				//on met à jour la liste
				WelcomeScreen.this.onRestart();
				dialog.dismiss();
			}// onClick(View)
		});

		//Annuler la suppression
		builder.setNegativeButton("NON", new DialogInterface.OnClickListener() {
			//@Override

			public void onClick(DialogInterface dialog, int which) {
				dialog.dismiss();
			}// onClick(View)
		});
		Dialog dialog_return = builder.create();
		dialog_return.show();
	}//deleteSchedule

	/**
	 * Affiche le détails d'un emploi du temps.
	 * Nom, date de création, date de dernière mise à jour.
	 */
	public void detailsDisplay() {
		Schedule s = null ;
		try {
			s = this.db.getScheduleWithName(this.nameCurrentSchedule);
			StringBuilder info = new StringBuilder() ;
			info.append("Nom : ");
			info.append(this.nameCurrentSchedule);
			info.append("\n");
			info.append("Crée le : ");
			info.append(s.getCreated());
			info.append("\n");
			info.append("Dernière mise à jour : ");
			String lm = s.getLastModif() ;
			if (lm.equalsIgnoreCase("null")) {
				lm = "Jamais" ;
			}// if
			info.append(lm);
			info.append("\n");

			AlertDialog.Builder builder = new AlertDialog.Builder(this);
			builder.setMessage(info.toString())
			.setTitle("Informations");
			builder.setIcon(RESULT_OK);
			builder.setNeutralButton("OK", null);
			Dialog dialog_return = builder.create();
			dialog_return.show();
		} catch (AAAException e) {
			// L'edt n'existe pas
			Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show() ;
		}// try
	}//detailsDisplay

	/**
	 * Renvoi vers la page de création d'un emploi du temps.
	 */
	public void addSchedule() {
		Intent intent = new Intent(WelcomeScreen.this, CreateScheduleScreen.class);
		this.startActivity(intent);
	}

	/**
	 * Renvoi vers la page de préférences de l'application.
	 */
	public void editOptions () {
		Intent intent = new Intent(WelcomeScreen.this, PreferencesScreen.class) ;
		this.startActivity(intent) ;
	}

	/**
	 * Met à jour tous les emplois du temps.
	 */
	protected void updateAllSchedules() {
		UpdateManager um = UpdateManager.getInstance() ;
		int nSchedules = this.adapter.getCount() ;
		for(int schedule=0; schedule<nSchedules; ++schedule) {
			um.addQueue(this.adapter.getItem(schedule)) ;
		}// for
	}

	/**
	 * Destruction de la mise en place de la synchronisation (écouteur)
	 */
	@Override
	protected void onDestroy() {
		super.onDestroy();
		//Détruire la mise en place de la synchronisation
		UpdateManager.getInstance().removeListener(this) ;
	}

	/**
	 * Mise à jour de la vue, lors d'une synchronisation.
	 * Change les icones en fonctions du niveau de synchonisation.
	 * @param args 
	 */
	public void onUpdate(Object... args) {
		if ((args.length >= 3) && (args[2] instanceof AAAException)) {
			AAAException ex = (AAAException) args[2] ;
			Toast.makeText(this, ex.getMessage(), Toast.LENGTH_LONG) ;
		}// if
		this.adapter.notifyDataSetChanged() ;
		UpdateManager um = UpdateManager.getInstance() ;
		int nSchedules = this.adapter.getCount() ;
		int schedule=0; 
		while ((schedule<nSchedules) 
				&& (um.getScheduleStatus(this.adapter.getItem(schedule)) != UpdateManager.STATUS_UPDATING)
				&& (um.getScheduleStatus(this.adapter.getItem(schedule)) != UpdateManager.STATUS_WAITING_FOR_UPDATE)) {
			++schedule ;
		}// while
		if (schedule >= nSchedules) {
			LoaderActionBarItem refreshItem = (LoaderActionBarItem) this.getActionBar().getItem(REFRESH) ;
			refreshItem.setLoading(false) ;
		}// if
	}

	/**
	 * Affiche une boite de dialogue pour quitter l'application si l'utilisateur appuye sur la touche retour sur l'écran d'accueil.
	 */
	@Override
	public void onBackPressed() {
		this.getQuitApplicationDialog() ;
	}

	/**
	 * Retourne le nom de l'emploi du temps courant.
	 * @return  nom de l'emploi du temps courant
	 */
	public String getNameCurrentSchedule() {
		return this.nameCurrentSchedule ;
	}

	/**
	 * Affiche une boite de dialogue pour quitter l'application avec demande de confirmation.
	 */
	protected void getQuitApplicationDialog() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this) ;
		builder.setMessage("Voulez vous-quittez l'application ?") ;
		builder.setIcon(RESULT_OK) ;

		builder.setPositiveButton("Oui", new QuitApplicationListener(this));

		builder.setNegativeButton("Annuler", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int which) {
				dialog.dismiss() ;
			}// onClick(View)
		}) ;

		builder.create().show() ;
	}// getQuitApplciationDialog()

	/**
	 * OnClickListener pour le bouton retour (physique ou autre).
	 * <p>Ecouteur de la boite de dialoge de fermeture de l'application.
	 * 
	 * @author  Zanette Sébastien, Andrianjafintrimo Victor
	 */
	class QuitApplicationListener implements DialogInterface.OnClickListener {
		/**
		 * Vue contenant le composant attaché à l'écouteur.
		 */    
		protected WelcomeScreen container ;

		/**
		 * Constructeur. 
		 * 
		 * @param 	container
		 * 			View containing the component attached to this listener
		 */
		public QuitApplicationListener(WelcomeScreen container) {
			super();
			this.container = container;
		}

		/**
		 * Définition des actions du clique sur le composant attaché.
		 * @param dialog doite de dialogue
		 * @param which choix (oui ou non)
		 */
		public void onClick(DialogInterface dialog, int which) {
			dialog.dismiss() ;
			this.container.finish() ;
		}// onClick(View)
	}




}
